#!/usr/bin/env python

import os
import urllib2
import urllib
import json
import time

import config

ASYNC_JOB_TIMEOUT    = config.ASYNC_JOB_TIMEOUT #second
ASYNC_JOB_CHECK_TIME = config.ASYNC_JOB_CHECK_TIME  #second

special_command_dict = {}
special_command_dict["enableStorageMaintenance"] = "prepareprimarystorageformaintenanceresponse"
special_command_dict["cancelStorageMaintenance"] = "cancelprimarystoragemaintenanceresponse"
special_command_dict["revokeSecurityGroupIngress"] = "revokesecuritygroupingress"

class HttpUtil:
  prefixURL = None

  def add_prefix(fn):
    """ The second arg must be url in fn """
    def _add_prefix(*args):
      if HttpUtil.prefixURL:
        url = HttpUtil.prefixURL + args[1]
      else:
        url = args[1]
      print "url=%s" % url
      args_len = len(args)
      if args_len == 2:
        return fn(args[0], url)
      elif args_len == 3:
        return fn(args[0], url, args[2])
      elif args_len == 4:
        return fn(args[0], url, args[2], args[3])
      else:
        raise Exception("HttpUtil args error")
    return _add_prefix

  def __init__(self, prefixURL=None):
    if prefixURL:
      HttpUtil.prefixURL = prefixURL
    else:
      HttpUtil.prefixURL = config.url

  @add_prefix
  def __http_get(self, url, headers=None):
    if headers is None:
      headers = {}
    req = urllib2.Request(url, None, headers)
    try:
      return urllib2.urlopen(req).read()
    except urllib2.HTTPError,ex:
      print ex.read()
      raise ex 

  @add_prefix
  def __http_post(self, url, data, headers=None):
    if data is None:
      raise Exception("data can't be None.")
    if headers is None:
      headers = {}
    req = urllib2.Request(url, data, headers)
    return urllib2.urlopen(req).read()

  def http_get(self, command, args={}, headers=None, response='json',async=False):
    return self.__http_request(command, headers=headers, args=args, response=response, async=async)

  def http_post(self, command, data, args={}, headers=None, response='json',async=False):
    return self.__http_request(command, data=data, headers=headers, args=args, response=response, async=async)

  def __http_request(self, command, data=None, headers=None, args={},response='json',async=False):
    """ private handle command request
    command: api name
    data: http data
    headers: http headers
    args: command args dict
    response: response type, default: json
    async: request type, default: False
    """
    args['command'] = command
    if response == 'json':
      args['response'] = 'json'

    query = urllib.urlencode(args)

    if data is None:
      response_str = self.__http_get(query)
    else:
      response_str = self.__http_post(query, data)

    response_obj = {}
    if response == 'json':
      response_obj = json.loads(response_str)
    else:
      raise Exception("unsupported response type")

    lower_command = command.lower()
    #command's response key
    if special_command_dict.has_key(command):
      command_resp_key = special_command_dict[command]
    else:
      command_resp_key = lower_command + 'response'

    if not command_resp_key in response_obj:
      raise Exception("can not find response key:" + command_resp_key + " in [" + ",".join(response_obj.keys()) + "]")

    command_result = response_obj[command_resp_key]

    if async:
      jobid = command_result["jobid"]
      command_result = self.__handle_async_job(jobid)

    return command_result

  def __handle_async_job(self, jobid):
    """ wait job result
    """
    command = "queryAsyncJobResult"
    args = {"jobid":jobid}
    job_response = self.http_get(command, args=args)
    job_status = job_response["jobstatus"]
    times = 0
    while job_status == 0 and ASYNC_JOB_TIMEOUT > times * ASYNC_JOB_CHECK_TIME: #while job pending and not timeout
      time.sleep(ASYNC_JOB_CHECK_TIME)
      job_response = self.http_get(command, args=args)
      job_status = job_response["jobstatus"]
      times += 1
  
    if job_status == 0:
      raise Exception("Asynchronous job timeout, jobid: %d" % jobid)
    elif job_status == 2:
      err = Exception('Asynchronous jobid: %d, exception %s: %s.' % (jobid, job_response["jobresultcode"], job_response["jobresult"]))
      err.response = job_response
      raise err

    job_result = job_response["jobresult"]
    return job_result

    
if __name__ == "__main__":
  test = HttpUtil("http://172.16.236.80:8096/client/api?")
  response = test.http_get("listVirtualMachines")
  print response

